{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# set up Python environment: numpy for numerical routines, and matplotlib for plotting\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "# display plots in this notebook\n",
    "%matplotlib inline\n",
    "\n",
    "# set display defaults\n",
    "plt.rcParams['figure.figsize'] = (10, 10)        # large images\n",
    "plt.rcParams['image.interpolation'] = 'nearest'  # don't interpolate: show square pixels\n",
    "plt.rcParams['image.cmap'] = 'jet'  # use grayscale output rather than a (potentially misleading) color heatmap\n",
    "\n",
    "## The caffe module needs to be on the Python path;\n",
    "#  we'll add it here explicitly.\n",
    "\n",
    "import sys\n",
    "caffe_root = '../caffe'  # this file should be run from {caffe_root}/examples (otherwise change this line)\n",
    "sys.path.insert(0, caffe_root + 'python')\n",
    "\n",
    "import caffe\n",
    "\n",
    "caffe.set_mode_cpu()\n",
    "\n",
    "model_def ='../models/AlexNet/deploy.prototxt'\n",
    "model_weights ='../models/AlexNet/bvlc_alexnet.caffemodel'\n",
    "\n",
    "net = caffe.Net(model_def,      # defines the structure of the model\n",
    "                model_weights,  # contains the trained weights\n",
    "                caffe.TEST)     # use test mode (e.g., don't perform dropout\n",
    "\n",
    "\n",
    "# create transformer for the input called 'data'\n",
    "transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})\n",
    "transformer.set_transpose('data', (2,0,1))  # move image channels to outermost dimension\n",
    "transformer.set_raw_scale('data', 255)      # rescale from [0, 1] to [0, 255]\n",
    "transformer.set_channel_swap('data', (2,1,0))  # swap channels from RGB to BGR\n",
    "\n",
    "# set the size of the input (we can skip this if we're happy\n",
    "#  with the default; we can also change it later, e.g., for different batch sizes)\n",
    "net.blobs['data'].reshape(10,        # batch size\n",
    "                          3,         # 3-channel (BGR) images\n",
    "                          227, 227)  # image size is 227x227\n",
    "\n",
    "image = caffe.io.load_image('../data/ILSVRC2012_img_val/ILSVRC2012_val_00000002.JPEG')\n",
    "transformed_image = transformer.preprocess('data', image)\n",
    "plt.imshow(image)\n",
    "\n",
    "# copy the image data into the memory allocated for the net\n",
    "net.blobs['data'].data[...] = transformed_image\n",
    "\n",
    "### perform classification\n",
    "output = net.forward()\n",
    "\n",
    "print 'Network data shape visualization'\n",
    "# for each layer, show the output shape\n",
    "for layer_name, blob in net.blobs.iteritems():\n",
    "    print layer_name + '\\t' + str(blob.data.shape)\n",
    "    \n",
    "    \n",
    "#Now look at the parameter shapes. The parameters are exposed as another `OrderedDict`, `net.params`. We need to index the resulting values with either `[0]` for weights or `[1]` for biases.\n",
    "# The param shapes typically have the form `(output_channels, input_channels, filter_height, filter_width)` (for the weights) and the 1-dimensional shape `(output_channels,)` (for the biases).\n",
    "\n",
    "print '\\n Network parameters shape visualization'\n",
    "\n",
    "for layer_name, param in net.params.iteritems():\n",
    "    print layer_name + '\\t' + str(param[0].data.shape), str(param[1].data.shape)\n",
    "    \n",
    "#Since we're dealing with four-dimensional data here, we'll define a helper function for visualizing sets of rectangular heatmaps.\n",
    "\n",
    "def vis_square(data,figureTitle):\n",
    "    \"\"\"Take an array of shape (n, height, width) or (n, height, width, 3)\n",
    "       and visualize each (height, width) thing in a grid of size approx. sqrt(n) by sqrt(n)\"\"\"\n",
    "    \n",
    "    # normalize data for display\n",
    "    data = (data - data.min()) / (data.max() - data.min())\n",
    "    \n",
    "    # force the number of filters to be square\n",
    "    n = int(np.ceil(np.sqrt(data.shape[0])))\n",
    "    padding = (((0, n ** 2 - data.shape[0]),\n",
    "               (0, 1), (0, 1))                 # add some space between filters\n",
    "               + ((0, 0),) * (data.ndim - 3))  # don't pad the last dimension (if there is one)\n",
    "    data = np.pad(data, padding, mode='constant', constant_values=1)  # pad with ones (white)\n",
    "    \n",
    "    # tile the filters into an image\n",
    "    data = data.reshape((n, n) + data.shape[1:]).transpose((0, 2, 1, 3) + tuple(range(4, data.ndim + 1)))\n",
    "    data = data.reshape((n * data.shape[1], n * data.shape[3]) + data.shape[4:])\n",
    "    \n",
    "    fig = plt.figure()\n",
    "    fig.suptitle(figureTitle, fontsize=15)\n",
    "    plt.imshow(data); plt.axis('off')\n",
    "    \n",
    "\n",
    "    \n",
    "    \n",
    "# First we'll look at the first layer filters, `conv1`\n",
    "\n",
    "filters = net.params['conv1'][0].data\n",
    "vis_square(filters.transpose(0, 2, 3, 1),'the parameters (weights) of the first conv Layer')\n",
    "\n",
    "\n",
    "feat = net.blobs['conv1'].data[0, :36]\n",
    "vis_square(feat,'The first layer output, conv1 (rectified responses of the filters above, first 36 only)')\n",
    "\n",
    "feat = net.blobs['pool5'].data[0]\n",
    "vis_square(feat,'The fifth layer after pooling, pool5')\n",
    "\n",
    "feat = net.blobs['fc6'].data[0]\n",
    "fig = plt.figure(figsize=(15, 3))\n",
    "fig.suptitle( 'The output of the first fully connected layer, fc6 (rectified)', fontsize=15)\n",
    "plt.xlabel('neuron index', fontsize=12)\n",
    "plt.ylabel('outout value', fontsize=12)\n",
    "plt.plot(feat.flat)\n",
    "\n",
    "fig = plt.figure(figsize=(15, 3))\n",
    "fig.suptitle('the PDF of the output', fontsize=15)\n",
    "plt.xlabel('output values', fontsize=12)\n",
    "plt.ylabel('number of neurons', fontsize=12)\n",
    "\n",
    "# 'show the output values and the histogram of the positive values'\n",
    "_ = plt.hist(feat.flat[feat.flat > 0], bins=100)\n",
    "\n",
    "feat = net.blobs['prob'].data[0]\n",
    "fig = plt.figure(figsize=(15, 3))\n",
    "fig.suptitle('The final probability output, `output layer`', fontsize=15)\n",
    "plt.xlabel('class', fontsize=12)\n",
    "plt.ylabel('prob', fontsize=12)\n",
    "plt.plot(feat.flat)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
